package cn.geminis.manage.service.controller;

import cn.geminis.core.data.query.QueryParameters;
import cn.geminis.core.util.PasswordUtils;
import cn.geminis.manage.core.entity.Administrator;
import cn.geminis.manage.service.model.AdminPasswordRepository;
import cn.geminis.manage.service.model.AdministratorRepository;
import cn.geminis.manage.service.model.RoleRepository;
import cn.geminis.web.logging.LoggingMethod;
import cn.geminis.web.logging.LoggingParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Allen
 */
@RestController
@RequestMapping("/administrators")
public class AdministratorController {

    @Autowired
    private AdministratorRepository repository;

    @Autowired
    private AdminPasswordRepository passwordRepository;

    @Autowired
    private RoleRepository roleRepository;

    @PostMapping
    @PreAuthorize("hasAuthority('manage')")
    public Page<Administrator> findPage(@RequestBody final QueryParameters queryParameters) {
        return this.repository.findPage(queryParameters);
    }

    @DeleteMapping
    @PreAuthorize("hasAuthority('manage')")
    @LoggingMethod("删除管理员")
    public void delete(@RequestBody @LoggingParam("用户名") List<String> ids) {
        ids.forEach(id -> this.repository.deleteById(id));
    }

    @PutMapping
    @PreAuthorize("hasAuthority('manage')")
    @LoggingMethod("保存管理员")
    public void save(@RequestBody @LoggingParam(value = "用户名", field = "id") Administrator administrator) {
        administrator.getAdminPassword().setId(administrator.getId());
        administrator.getAdminPassword().setPasswordChangeTime(LocalDateTime.now());

        var salt = PasswordUtils.createSalt();
        var saltPassword = PasswordUtils.addSalt(administrator.getAdminPassword().getPassword(), salt);
        administrator.getAdminPassword().setPassword(saltPassword);
        administrator.getAdminPassword().setSalt(salt);

        this.repository.save(administrator);
    }

    @PutMapping("/{id}/resetPassword")
    @PreAuthorize("hasAuthority('manage')")
    @LoggingMethod("重置管理员密码")
    public void resetPassword(@PathVariable @LoggingParam("用户名") String id, String password) {
        var adminPassword = passwordRepository
                .where("id", id)
                .findOne()
                .orElseThrow(() -> new RuntimeException("管理员不存在：" + id));

        var salt = PasswordUtils.createSalt();
        var saltPassword = PasswordUtils.addSalt(password, salt);

        adminPassword.setPassword(saltPassword);
        adminPassword.setPassword2(null);
        adminPassword.setPassword3(null);
        adminPassword.setSalt(salt);
        adminPassword.setPasswordChangeTime(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
        this.passwordRepository.save(adminPassword);
    }

    @PutMapping("/{id}/role")
    @PreAuthorize("hasAuthority('manage')")
    @LoggingMethod("设置管理员角色")
    public void role(@PathVariable @LoggingParam("用户名") String id, @RequestBody List<String> roles) {
        var admin = this.repository.findById(id).orElseThrow(() -> new RuntimeException("管理员不存在：" + id));
        var rs = this.roleRepository.findAllById(roles);

        admin.setRoles(new HashSet<>(rs));

        this.repository.save(admin);
    }

    @GetMapping("/{id}/functions")
    @PreAuthorize("hasAuthority('manage')")
    public List<String> userFunctions(@PathVariable String id) {
        return this.repository
                .include("roles.functions")
                .where("id", id)
                .findOne().get()
                .getRoles().stream()
                .flatMap(role -> role.getFunctions().stream())
                .map(function -> function.getId())
                .collect(Collectors.toList());
    }

}
